package IC;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

 



import IC.AST.ICClass;
import IC.AST.PrettyPrinter;
import IC.AST.Program;
import IC.Parser.*;
import IC.Semantic.SemanticChecker;
import IC.Semantic.SymbolTableBuilder;
import IC.Tables.Symbols.GlobalSymbolTable;
import IC.Tables.Types.TypeTable;
public class Compiler
{
    public static void main(String[] args)
    {
		boolean libraryFileSpecified = false, printAST = false, dumpSymtab = false;
		String libPath = "";
		  
		Program root =null;
		ICClass Lroot = null;
		
		if (args.length < 1 || args.length>4 )
		{
			System.out.println("Usage: java IC.Compiler <file.ic> [ -L</path/to/libic.sig> ] [-print-ast] [-dump-symtab]");
			System.exit(-1);
		}
		for (int i=1; i< args.length; i++)
	    {
			if (args[i].equals("-print-ast"))
			{   	
				printAST = true;
			}

		    if (args[i].startsWith("-L"))
		    {
		    	libraryFileSpecified = true;
		    	libPath = args[i].substring(2, args[i].length());
		        
		    }
		    
			if (args[i].equals("-dump-symtab"))
			{   	
				dumpSymtab = true;
			}
		    
		    
	    }
		
		
	    if (libraryFileSpecified) 
	    {

	    	try 
	    	{
	            FileReader libicFile = new FileReader(libPath);
	            Lexer scanner = new Lexer(libicFile);
	            LibraryParser Lparser = new LibraryParser(scanner);
	            Lroot = (ICClass) Lparser.parse().value;
	            System.out.println("parsed " + libPath + " successfully!");
	            
	            if(printAST)
	            {
	            	PrettyPrinter printer = new PrettyPrinter(args[1].substring(2, args[1].length()));
					System.out.println(printer.visit(Lroot));
	            }
	            	
	        }
	    	catch (SyntaxError e) 
	    	{
	        	System.out.print("in " + libPath + "\n" + e +"\n");
	        }
        
	    	catch (FileNotFoundException e)
	    	{
        		System.out.println("File Not Found: " + libPath);
	    	}
	    	catch (IOException e)
	    	{
	    		System.out.println("Error readin file: " + libPath);
	    	}
	    	catch (Exception e)
	    	{
        			System.out.println(e);
	    	}
	    }

		
		
		try
		{
			FileReader txtFile = new FileReader(args[0]);
			Lexer scanner = new Lexer(txtFile);
			Parser parser = new Parser(scanner);
	    	root = (Program) parser.parse().value;
	    	System.out.println("Parsed " + args[0] + " successfully!");
	        
	    	if (printAST)
	    	{
	    		PrettyPrinter printer = new PrettyPrinter(args[0]);
	    		System.out.println(printer.visit(root));
	    	}	  
	    	
	    	if (libraryFileSpecified)
	    		root.AddClass(Lroot);
	    	SymbolTableBuilder symbolTableBuilder = new SymbolTableBuilder(args[0]);
			Object globalSymbolTable = root.accept(symbolTableBuilder);
			if (globalSymbolTable == null){
				System.err.println("Failed to build a symbol table");
				System.exit(-1); 
			}
			
			if (dumpSymtab){
				System.out.println("\n"+globalSymbolTable);
				System.out.println(TypeTable.dumpSymbolTable());
			}
			
			// other semantic checks: variables usage correctness, type checks, scoping rules
			SemanticChecker defTypeSemanticChecker = new SemanticChecker((GlobalSymbolTable)globalSymbolTable);
			Object semanticChecks = root.accept(defTypeSemanticChecker);
			if (semanticChecks == null) {
				System.out.println("Encountered an error while type-checking");
				System.exit(-1); // in case of a semantic error
			} else {
				System.out.println("Passed type-checking");
			}
	    	
		}
	    catch (SyntaxError e) 
	    {
	    	System.out.println("in " + args[0] + "\n" + e +"\n");
	    } 
	    catch (FileNotFoundException e)
	    {
	    	System.out.println("File Not Found: " + e);
	    }
	  
	    catch (Exception e)
	    {
	    	System.out.println(e); 
	    }
    }
}
